home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 134_01.zip / RETAB.C < prev    next >
Text File  |  1993-06-12  |  5KB  |  238 lines

  1. /*    RETAB.C        */
  2.  
  3. /*    This code is in the public domain    */
  4.  
  5. /*    The following program is written to illustrate the use of
  6.    coroutines to simulate Unix-style pipelines.  It consists of the
  7.    Software Tools programs "entab" and "detab", hooked together:
  8.  
  9.     detab | entab
  10.  
  11.     Each command is implemented as a coroutine; the GETCHAR and
  12.    PUTCHAR over the pipeline is replaced with the appropriate RESUME.
  13.    Perhaps some ambitious hacker can build a general pipeline mechanism
  14.    atop the coroutine package?
  15. */
  16.  
  17. #include <bdscio.h>
  18. #include <dio.h>
  19. #include <coro.h>
  20. #include <cmdutil.h>
  21.  
  22. /*    External storage    */
  23.  
  24. /*    Storage for the tab positions for entab and detab    */
  25.  
  26. char ntabpos [MAXLINE];
  27. char dtabpos [MAXLINE];
  28.  
  29. /*    Coroutine FCV pointers    */
  30.  
  31. struct c_fcv_ * ntabco;
  32. struct c_fcv_ * dtabco;
  33.  
  34. /*    Main program    */
  35.  
  36. main (argc, argv)
  37.     int argc;
  38.     char ** argv;
  39.     {
  40.  
  41.     int entab ();        /* "Main program" of the ENTAB coroutine */
  42.     int detab ();        /* "Main program" of the DETAB coroutine */
  43.  
  44.     _allocp = NULL;        /* pre-1.5: Initialize the allocator    */
  45.  
  46.     dioinit (&argc, argv);    /* Initialize directed I/O         */
  47.  
  48.     getopt (argc, argv);    /* Process command line options        */
  49.  
  50.     /*    Create the two coroutines, giving each 1K bytes of stack
  51.        space.  */
  52.  
  53.     ntabco = c_create (&entab, 1024);
  54.     dtabco = c_create (&detab, 1024);
  55.  
  56.     /*    The following call wakes up the "entab" coroutine.  The
  57.        first character it needs will wake up the "detab" coroutine
  58.        via "c_resume".  The first of the two coroutines to terminate
  59.        (via detach or return) will come back here.
  60.     */
  61.  
  62.     c_call (ntabco);
  63.  
  64.     /*    One or the other coroutine has terminated.  If "detab"
  65.        ended prematurely, pass an EOF on to "entab" to get it to
  66.        quit.
  67.     */
  68.  
  69.     if (c_passer () == dtabco) c_call (ntabco, EOF);
  70.  
  71.     /*    All done; kill the two coroutines.    */
  72.  
  73.     c_destroy (dtabco);
  74.     c_destroy (ntabco);
  75.  
  76.     /*    Get rid of redirected I/O    */
  77.  
  78.     dioflush ();
  79.  
  80.     /* Th-th-th-that's all, folks. */
  81.  
  82.     }
  83.  
  84. /*    GETOPT procedure.    */
  85.  
  86. /*    The following procedure reads the tab stops from the command line
  87.    and installs them into the "ntabpos" and "dtabpos" arrays.    */
  88.  
  89. getopt (argc, argv)
  90.     int argc;
  91.     char ** argv;
  92.     {
  93.     struct option optable [3];
  94.     int *info;
  95.  
  96.     initv (optable, EOF,
  97.         "Detab", MNVL_KWD,
  98. #define DETAB_OPT 0
  99.         "eNtab", MNVL_KWD,
  100. #define ENTAB_OPT 1
  101.         EOF);
  102.  
  103.     ++argv;            /* Discard command name */
  104.     --argc;
  105.  
  106.     deftab (dtabpos);    /* Set up default tab stops */
  107.     deftab (ntabpos);
  108.  
  109.     while (argc) {        /* Process the command line */
  110.  
  111.         switch (procarg (&argc, &argv, optable, &info)) {
  112.         case DETAB_OPT:
  113.             settab (dtabpos, info);
  114.             break;
  115.         case ENTAB_OPT:
  116.             settab (ntabpos, info);
  117.             break;
  118.         default:
  119.             showsyntax ("retab", optable);
  120.             exit ();
  121.         }
  122.         }
  123.     }
  124.  
  125. /*    Define default tab stops (same as CP/M)        */
  126.  
  127. deftab (posns)
  128.     char *posns;        /* Vector defining tab positions */
  129.     {
  130.     int i;
  131.  
  132.     for (i=1; i<MAXLINE; ++i)
  133.         posns [i] = ((i % 8) == 1); /* Position 1 and every 8
  134.                         columns thereafter */
  135.     }
  136.  
  137. /*    Define user-specified tab stops        */
  138.  
  139. settab (posns, info)
  140.     char *posns;            /* Vector defining tab positions */
  141.     int *info;            /* Command line argument list */
  142.     {
  143.     int i;
  144.     int j;
  145.     int prevpos;
  146.  
  147.     prevpos = 1;
  148.  
  149.     setmem (posns, MAXLINE, 0);    /* Initialize to no tabs */
  150.  
  151.     for (i=1; i <= *info; ++i) {    /* Loop thru specified positions */
  152.         if (info [i] >= 0) {
  153.             posns [info [i]] = TRUE;
  154.             prevpos = i;
  155.             }
  156.         else {
  157.             for (j = prevpos; j < MAXLINE; j -= info [i])
  158.                 posns [j] = TRUE;
  159.             }
  160.         }
  161.     }
  162.  
  163. /*    DETAB procedure        */
  164.  
  165. /*    This is the DETAB coroutine.  With the exception of the fact that
  166.    it uses RESUME instead of PUTCHAR, it's straight out of Software Tools */
  167.  
  168. detab () {
  169.     int col;        /* Current column within the line */
  170.     int c;            /* Current character */
  171.  
  172.     col = 1;
  173.  
  174.     while ((c = getchar ()) != EOF && c != CPMEOF) {
  175.                 /* Read a character from source file */
  176.  
  177.         if (c == '\t') {    /* TAB */
  178.             do {
  179.                 c_resume (ntabco, ' ');
  180.                 ++col;
  181.                 } while (col < MAXLINE && !dtabpos [col]);
  182.             }
  183.  
  184.         else if (c == '\r' || c == '\n') {
  185.                     /* CR, NEWLINE */
  186.             c_resume (ntabco, c);
  187.             col = 1;
  188.             }
  189.  
  190.         else {            /* Anything else */
  191.             c_resume (ntabco, c);
  192.             ++col;
  193.             }
  194.         }
  195.     }
  196.  
  197. /*    ENTAB coroutine        */
  198.  
  199. /*    Just like DETAB, this one is straight out of SOFTWARE TOOLS.  It
  200.    calls RESUME instead of GETCHAR to get its input from the pipeline. */
  201.  
  202. entab () {
  203.     int col;        /* Current column in line */
  204.     int newcol;        /* Column following a tab */
  205.     int c;            /* Current character */
  206.  
  207.     col = 1;
  208.  
  209.     while (1) {
  210.         newcol = col;
  211.  
  212.         while ((c = c_resume (dtabco)) == ' ') {
  213.             ++newcol;
  214.             if (ntabpos [newcol]) {
  215.                 putchar ('\t');
  216.                 col = newcol;
  217.                 }
  218.             }
  219.  
  220.         for ( ; col < newcol; ++col) putchar (' ');
  221.  
  222.         if (c == EOF) return;
  223.  
  224.         putchar (c);
  225.  
  226.         if (c == '\n' || c == '\r')
  227.             col = 1;
  228.         else
  229.             ++col;
  230.         }
  231.     }
  232. character from source file */
  233.  
  234.         if (c == '\t') {    /* TAB */
  235.             do {
  236.                 c_resume (ntabco, ' ');
  237.                 ++col;
  238.